﻿using zijian666.Data;

namespace zijian666.Data.SqlElements;

/// <summary>
/// 表示一个 SQL 元素。
/// </summary>
public interface ISqlElement
{
    /// <summary>
    /// 将 SQL 元素追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>

    bool Append([NotNullWhen(true)] FormattableSql sql);

    bool IsEmpty { get; }
}

/// <summary>
/// 表示一个 SQL 查询。
/// </summary>
/// <param name="Select">SQL 选择部分。</param>
/// <param name="Table">SQL 表。</param>
/// <param name="Where">SQL 条件。</param>
/// <param name="OrderBy">SQL 排序。</param>
public readonly record struct SqlQuery(SqlSelect Select, SqlTable Table, SqlWhere Where, SqlOrderBy OrderBy) : ISqlElement
{
    /// <summary>
    /// 将 SQL 查询追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null)
        {
            return false;
        }
        sql.AppendString("SELECT ");
        Select.Append(sql);
        sql.AppendString(" FROM ");
        Table.Append(sql);
        Where.Append(sql);
        OrderBy.Append(sql);
        return true;
    }

    public bool IsEmpty => Table.IsEmpty;
}

/// <summary>
/// 表示一个 SQL 选择部分。
/// </summary>
/// <param name="Function">SQL 函数。</param>
/// <param name="Columns">SQL 列集合。</param>
public readonly record struct SqlSelect(string Function, IEnumerable<SqlColumn> Columns) : ISqlElement
{
    /// <summary>
    /// 将 SQL 选择部分追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null)
        {
            return false;
        }

        if (!string.IsNullOrWhiteSpace(Function))
        {
            sql.AppendString(Function);
            if (Columns is null)
            {
                return true;
            }
            sql.AppendString(" ");
        }

        if (Columns?.Any() is true)
        {
            var ee = Columns.GetEnumerator();
            if (ee.MoveNext())
            {
                ee.Current.Append(sql);
                while (ee.MoveNext())
                {
                    sql.AppendString(", ");
                    ee.Current.Append(sql);
                }
            }
        }
        else
        {
            sql.AppendString("*");
        }
        return true;
    }

    public bool IsEmpty => false;
}

/// <summary>
/// 表示一个 SQL 条件部分。
/// </summary>
/// <param name="Condition">SQL 条件。</param>
public readonly record struct SqlWhere(SqlCondition Condition) : ISqlElement
{
    /// <summary>
    /// 将 SQL 条件部分追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null || IsEmpty)
        {
            return false;
        }
        sql.AppendString(" WHERE ");
        if (!Condition.Append(sql))
        {
            sql.AppendString("1=2");
        }
        return true;
    }

    public bool IsEmpty => Condition.IsEmpty;
}

/// <summary>
/// 表示一个 SQL 条件。
/// </summary>
/// <param name="Column">SQL 列。</param>
/// <param name="Operator">SQL 操作符。</param>
/// <param name="Value">SQL 值。</param>
public readonly record struct SqlCondition(SqlColumn Column, SqlOperatorAttribute Operator, object[]? Value) : ISqlElement
{
    /// <summary>
    /// 创建一个表示 true 的 SQL 条件。
    /// </summary>
    public static SqlCondition True() => new(default, SqlOperator.True, []);

    /// <summary>
    /// 创建一个表示 false 的 SQL 条件。
    /// </summary>
    public static SqlCondition False() => new(default, SqlOperator.False, []);

    /// <summary>
    /// 创建一个表示 OR 的 SQL 条件。
    /// </summary>
    /// <param name="items">SQL 条件集合。</param>
    public static SqlCondition Or(IEnumerable<SqlCondition> items) => items.Take(2).Count() switch
    {
        0 => default,
        1 => items.First(),
        _ => new(default, SqlOperator.Or, [items])
    };

    /// <summary>
    /// 创建一个表示 AND 的 SQL 条件。
    /// </summary>
    /// <param name="items">SQL 条件集合。</param>
    public static SqlCondition And(IEnumerable<SqlCondition> items) => items.Take(2).Count() switch
    {
        0 => default,
        1 => items.First(),
        _ => new(default, SqlOperator.And, [items])
    };

    /// <summary>
    /// 将 SQL 条件追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null || IsEmpty)
        {
            return false;
        }
        var column = Column;
        var args = Value;
        var op = Operator;

        if (op.ParametersLength == 0)
        {
            sql.AppendFormat(op.FormatExpression);
        }
        else if (op.ParametersLength == 1)
        {
            sql.AppendFormat(op.FormatExpression, [column.ColumnName]);
        }
        else if (op.ParametersLength - 1 != args?.Length)
        {
            //throw new ArgumentException($"参数个数不匹配，期望 {op.ParametersLength} 个参数，实际 {args?.Length ?? 0} 个。");
            sql.AppendString($"/*{column.Name} 条件参数个数不匹配，期望 {op.ParametersLength - 1} 个参数，实际 {args?.Length ?? 0} 个。*/");
            return false;
        }
        else
        {
            sql.AppendFormat(op.FormatExpression, [column.ColumnName, .. args]);
        }
        return true;
    }

    public bool IsEmpty => Operator is null;
}

/// <summary>
/// 表示一个 SQL 排序部分。
/// </summary>
/// <param name="Items">排序项集合。</param>
public readonly record struct SqlOrderBy(IEnumerable<OrderItem> Items) : ISqlElement
{
    /// <summary>
    /// 将 SQL 排序部分追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null || IsEmpty)
        {
            return false;
        }
        sql.AppendString(" ORDER BY ");

        var ee = Items.GetEnumerator();
        if (ee.MoveNext())
        {
            ee.Current.Append(sql);
            while (ee.MoveNext())
            {
                sql.AppendString(" ,");
                ee.Current.Append(sql);
            }
        }

        return true;
    }

    public bool IsEmpty => Items is null || !Items.Any();
}

/// <summary>
/// 表示一个排序项。
/// </summary>
/// <param name="Column">SQL 列。</param>
/// <param name="IsDescending">是否降序。</param>
public readonly record struct OrderItem(SqlColumn Column, bool IsDescending) : ISqlElement
{
    /// <summary>
    /// 将排序项追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (Column.Append(sql))
        {
            sql.AppendString(IsDescending, " DESC");
            return sql is not null;
        }
        return false;
    }

    public bool IsEmpty => Column.IsEmpty;
}

/// <summary>
/// 表示一个 SQL 列。
/// </summary>
/// <param name="table">SQL 表。</param>
/// <param name="Name">列名。</param>
public readonly record struct SqlColumn(SqlTable table, string Name) : ISqlElement
{
    public string? Function { get; init; }
    /// <summary>
    /// 获取列名。
    /// </summary>
    public string ColumnName => table.Scheam?.GetColumnName(Name) ?? Name;

    /// <summary>
    /// 将 SQL 列追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null || IsEmpty)
        {
            return false;
        }
        if (string.IsNullOrWhiteSpace(Function))
        {
            sql.AppendFormat("{0:##}", ColumnName);
        }
        else
        {
            sql.AppendString(Function);
            sql.AppendFormat("({0:##})", ColumnName);
        }
        return true;
    }

    public bool IsEmpty => string.IsNullOrWhiteSpace(ColumnName);
}

/// <summary>
/// 表示一个 SQL 表。
/// </summary>
/// <param name="Name">表名。</param>
/// <param name="EntityType">实体类型。</param>
public readonly record struct SqlTable(string? Name, Type? EntityType = null) : ISqlElement
{
    /// <summary>
    /// 获取实体信息。
    /// </summary>
    public EntityScheam Scheam { get; } = EntityScheam.Get(EntityType ?? typeof(object));

    /// <summary>
    /// 获取表名。
    /// </summary>
    public string TableName => string.IsNullOrWhiteSpace(Name) ? Scheam?.TableName : Name;

    /// <summary>
    /// 将字符串隐式转换为 <see cref="SqlTable"/>。
    /// </summary>
    /// <param name="name">表名。</param>
    public static implicit operator SqlTable(string name) => new(name);

    /// <summary>
    /// 将 SQL 表追加到 <see cref="FormattableSql"/> 实例中。
    /// </summary>
    /// <param name="sql">要追加到的 <see cref="FormattableSql"/> 实例。</param>
    /// <returns>如果追加成功，则返回 true；否则返回 false。</returns>
    public bool Append(FormattableSql sql)
    {
        if (sql is null || IsEmpty)
        {
            return false;
        }
        sql.AppendFormat("{0:##}", TableName);
        return true;
    }

    public bool IsEmpty => string.IsNullOrWhiteSpace(TableName);
}
